package com.ai_chat.sys.service.impl;

import com.ai_chat.common.util.EmailUtil;
import com.ai_chat.common.util.JwtUtil;
import com.ai_chat.common.vo.CodeType;
import com.ai_chat.sys.entity.RegistrationDTO;
import com.ai_chat.sys.entity.TokenInfo;
import com.ai_chat.sys.entity.User;
import com.ai_chat.sys.entity.WeChatUser;
import com.ai_chat.sys.mapper.UserMapper;
import com.ai_chat.sys.service.IUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;


@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Autowired
    private EmailUtil emailUtil;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private JwtUtil jwtUtil;


    @Resource
    private RestTemplate restTemplate;

    public Integer sendVerificationCode(String email){

        String value = redisTemplate.opsForValue().get(email);
        //redis里没有这个邮箱为key的数据。发送验证码，并插入该kv到redis中。
        if(value == null){
            Random random = new Random();
            String verificationCode = String.valueOf(random.nextInt(100000,1000000));

            String text = "您正在进行AI_CHAT账号注册，验证码为：" + verificationCode + "（有效时间：10分钟）";

            if(emailUtil.sendMail(email,"AI_CHAT注册验证码",text)){
                //确定邮箱发送成功。
                //第一次给该邮箱发送验证码，将其存入redis，10分钟有效。但为了更长时间记录这个邮件的动向，redis里过期时间设成30分钟。
                value = verificationCode + "1";
                redisTemplate.opsForValue().set(email,value,30, TimeUnit.MINUTES);

                return CodeType.OK;
            }else {
                //邮箱发送失败
                return CodeType.EMAIL_SEND_FAIL;
            }
        }
        //redis里存有这个邮箱为key的数据
        else{
            //检查已经调用的次数。达到5次什么都不做，即该邮箱被拉入小黑屋。没达到5次就再次发送验证码，并增加调用次数
            int cnt = Integer.parseInt(value.substring(6));
            if(cnt >= 5){
                //连续访问达到5次，拉黑屋5小时处理
                redisTemplate.expire(email,5,TimeUnit.HOURS);

                return CodeType.BEING_BLACKLISTED;
            }else{
                //未达到5次，且没有达到验证码的过期时间，就重新生成验证码
                //没达到验证码的过期时间重新发送验证码，旧验证码就失效了。达到了过期时间发送验证码自然就是生成一份新验证码。
                Random random = new Random();
                String verificationCode = String.valueOf(random.nextInt(100000,1000000));

                String text = "您正在进行AI_CHAT账号注册，验证码为：" + verificationCode + "（有效时间：10分钟）";
                boolean sendSuccess = emailUtil.sendMail(email,"AI_CHAT注册验证码",text);
                if(sendSuccess){
                    //确定邮箱发送成功。
                    value = verificationCode + (cnt+1);
                    redisTemplate.opsForValue().set(email,value,30,TimeUnit.MINUTES);
                    return CodeType.OK;
                }else {
                    //邮箱发送失败
                    return CodeType.EMAIL_SEND_FAIL;
                }
            }
        }
    }


    public Integer register(RegistrationDTO registrationDTO){

        String value = redisTemplate.opsForValue().get(registrationDTO.getEmail());


        //redis里存在邮箱的记录
        if(value != null){
            Long remainExpiration = redisTemplate.getExpire(registrationDTO.getEmail(), TimeUnit.MINUTES);
            if(value.startsWith(registrationDTO.getCode())){
                //过期时间故意延长过，验证码的有效时间要做减法
                if(remainExpiration - 20 > 0){
                    LambdaQueryWrapper<User> condition = new LambdaQueryWrapper<>();
                    condition.eq(User::getEmail,registrationDTO.getEmail());

                    User user = userMapper.selectOne(condition);

                    if(user == null){
                        User newUser = new User();
                        newUser.setNickname(registrationDTO.getNickname());
                        newUser.setEmail(registrationDTO.getEmail());
                        newUser.setPasswd(registrationDTO.getPasswd());


                        userMapper.registerUserByEmailPasswd(newUser.getNickname(),newUser.getEmail(),newUser.getPasswd());

                        return CodeType.OK;
                    }
                    return CodeType.EMAIL_REGISTERED;
                }
                else {
                    return CodeType.VERIFICATION_CODE_EXPIRED;
                }
            }
        }

        return CodeType.VERIFICATION_CODE_ERROR;

    }

    public Map<String,Object> login(User user) {
        LambdaQueryWrapper<User> condition = new LambdaQueryWrapper<>();
        condition.eq(User::getEmail,user.getEmail());
        condition.eq(User::getPasswd,user.getPasswd());

        User loginUser = this.baseMapper.getLoginUserByEmailPasswd(user.getEmail(),user.getPasswd());
        if(loginUser != null){
            //构建jwt，到时候要传递给前端。
            loginUser.setPasswd(null);
            loginUser.setToken(null);
            String token = jwtUtil.createToken(loginUser);

            Map<String,Object> data = new HashMap<>();
            data.put("id",loginUser.getId());
            data.put("nickname",loginUser.getNickname());
            data.put("email",loginUser.getEmail());
            data.put("Authorization",token);
            return data;
        }
        return null;
    }

    public WeChatUser getWechatUserInfo(String code){
        String tokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + "wx317d50ff8442777d" +
                "&secret=" + "87954ceb586e570d964123ec79f06640" + "&code=" + code + "&grant_type=authorization_code";
        ResponseEntity<TokenInfo> result = restTemplate.getForEntity(tokenUrl, TokenInfo.class);
        TokenInfo tokenInfo = result.getBody();

        //用accessToken获取扫码用户的个人信息
        String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + tokenInfo.getAccess_token()
                + "&openid=" + tokenInfo.getOpenid() + "&lang=zh_CN";
        ResponseEntity<WeChatUser> weChatUser = restTemplate.getForEntity(userInfoUrl, WeChatUser.class);

        return weChatUser.getBody();
    }

    public Map<String,Object> wechatTryLogin(User user){
        LambdaQueryWrapper<User> condition = new LambdaQueryWrapper<>();
        condition.eq(User::getWechatOpenid,user.getWechatOpenid());
        User loginUser = userMapper.selectOne(condition);

        if(loginUser != null){
            loginUser.setPasswd(null);
            loginUser.setToken(null);
            String token = jwtUtil.createToken(loginUser);

            Map<String,Object> data = new HashMap<>();
            data.put("id",loginUser.getId());
            data.put("nickname",loginUser.getNickname());
            data.put("email",loginUser.getEmail());
            data.put("Authorization",token);

            return data;
        }

        return null;
    }




    public User getUserTokenByUserId(Integer id){
        return userMapper.selectById(id);
    }

    public void updateUserToken(User user){
        userMapper.updateById(user);
    }


    public Map<String,Object> wechatBindWithHasAccount(User user){
        Integer result = userMapper.bindWechatOpenid(user.getWechatOpenid(),user.getEmail(),user.getPasswd());
        if(result == 0){
            return null;
        }
        else{
            User loginUser = userMapper.getLoginUserByEmailPasswd(user.getEmail(),user.getPasswd());
            loginUser.setPasswd(null);;
            loginUser.setToken(null);;
            String Auth = jwtUtil.createToken(loginUser);

            Map<String,Object> data = new HashMap<>();
            data.put("id",loginUser.getId());
            data.put("nickname",loginUser.getNickname());
            data.put("email",loginUser.getEmail());
            data.put("Authorization",Auth);
            return data;

        }
    }


    public Map<String,Object> query(Integer id) {
        LambdaQueryWrapper<User> condition = new LambdaQueryWrapper<>();
        condition.eq(User::getId,id);
        User user = userMapper.selectOne(condition);
        Map<String,Object> data=new HashMap<>();
        data.put("nickname",user.getNickname());
        data.put("email",user.getEmail());
        data.put("token",user.getToken());
        return data;
    }


    @Override
    public void editUserNickName(Integer id, String nickname) {
        LambdaQueryWrapper<User> condition = new LambdaQueryWrapper<>();
        condition.eq(User::getId,id);
        User user = userMapper.selectOne(condition);
        System.out.println(nickname);
        user.setNickname(nickname);

        userMapper.updateById(user);
        System.out.println(user);
    }

    @Override
    public void editUserPassword(Integer id, String password) {

        userMapper.editUserPassword(password,id);
    }

    @Override
    public boolean PsEqual(Integer id, String prepassword) {
        User user = userMapper.PsEqual(id,prepassword);
        return user != null;

    }

}